package com.barney.support.web.test;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.DefaultHandler;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.util.Scanner;

/**
 * Jetty를 사용하는 웹 서버.
 * 개인이 개발할 때 사용하는 것을 목적으로 한다.
 */
public class JettyWebServer {

	private final Integer port;
	private final String webapp;
	private final String webappConfiguration;
	private final List<File> classpaths;
	private Server server;
	private WebAppContext webAppContext;
	private boolean reloadable = true;

	/**
	 * Jetty 웹 서버를 생성한다.
	 *
	 * @param port 웹 서버가 사용할 포트 번호
	 * @param webapp 웹 어플리케이션의 디렉토리
	 * @param webappConfiguration 웹 어플리케이션이 사용하는 설정파일 (jetty-web.xml)
	 * @param requiredClasspaths 웹 어플리케이션의 클래스 패스들
	 */
	public JettyWebServer(Integer port, String webapp, String webappConfiguration,
			String... requiredClasspaths) {
		this.port = port;
		this.webapp = webapp;
		this.webappConfiguration = webappConfiguration;
		this.classpaths = new ArrayList<File>();
		for (String each : requiredClasspaths) {
			classpaths.add(new File(each));
		}
	}

	/**
	 * 클래스가 변경되었는지를 감시하여 컨텍스트를 다시 시작할 지 여부를 설정한다.
	 *
	 * @param reloadable
	 */
	public void setReloadable(boolean reloadable) {
		this.reloadable = reloadable;
	}

	/**
	 * 웹 서버를 시작한다.
	 */
	public void start() throws Exception {
		server = new Server();

		prepareServerConfiguration();
		prepareHttpConnector();
		prepareWebAppContext();
		prepareReloadable();

		server.start();
	}

	/**
	 * 웹 서버를 중지한다.
	 */
	public void stop() throws Exception {
		server.stop();
	}

	private void prepareServerConfiguration() {
		server.setStopAtShutdown(true);
	}

	private void prepareReloadable() {
		if (!reloadable)
			return;
		Scanner scanner = new Scanner();
		scanner.setReportExistingFilesOnStartup(false);
		scanner.setScanInterval(3);
		scanner.setScanDirs(classpaths);
		scanner.setRecursive(true);
		scanner.addListener(new JettyWebServerListener(webAppContext, classpaths));
		scanner.start();
	}

	private void prepareWebAppContext() throws IOException {
		webAppContext = new WebAppContext(webapp, "/");
		if (webappConfiguration != null) {
			webAppContext.setDefaultsDescriptor(webappConfiguration);
		}
		server.addHandler(webAppContext);

		DefaultHandler defaultHandler = new DefaultHandler();
		defaultHandler.setServeIcon(false);
		server.addHandler(defaultHandler);
	}

	private void prepareHttpConnector() {
		SelectChannelConnector httpConnector = new SelectChannelConnector();
		httpConnector.setForwarded(true);
		httpConnector.setPort(port);
		server.addConnector(httpConnector);
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("JettyWebServer");
		builder.append(Server.getVersion());
		builder.append(" [port=");
		builder.append(port);
		builder.append(", webapp=");
		builder.append(webapp);
		builder.append(", webappConfiguration=");
		builder.append(webappConfiguration);
		builder.append(", classpaths=");
		builder.append(classpaths);
		builder.append("]");
		return builder.toString();
	}
}
// EOF